using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Threading;

using EnterpriseDT.Net.Ftp;


namespace StormModelToKMLDB
{
    public class NHCGetter
    {
        #region Events
        /// <summary>
        /// Handler for when the ModelGetter successfully retrieves storms
        /// </summary>
        /// <param name="models">the list of Storm objects that it built from NHC data</param>
        public delegate void DiscussionRetrievedHandler(List<NHCDiscussion> models);
        /// <summary>
        /// The event that fires when the ModelGetter successfully retrieves storms
        /// </summary>
        public event DiscussionRetrievedHandler DiscussionRetrieved;
        #endregion

        #region Private Members
        /// <summary>
        /// Thread that polls NHC ftp for new data, and subsequently builds storm objects from the data.
        /// </summary>
        private Thread _getNHCThread;
        /// <summary>
        /// The ftp client that connects to the NHC server and retrieves the raw data
        /// </summary>
        private FTPClient _ftp;
        /// <summary>
        /// Time delta between ftp polls for NHC data
        /// </summary>
        private int _sleepMillis;
        #endregion

        #region Constructors
        public NHCGetter(int sleepMinutes)
        {
            _ftp = new FTPClient();
            _sleepMillis = sleepMinutes * 1000 * 60;

            // Start Get Thread
            this._getNHCThread = new Thread(new ThreadStart(this.RunGetNHSThread));
            this._getNHCThread.Name = "NHCGetterThread";
            this._getNHCThread.IsBackground = true;
        }
        #endregion

        #region Public Methods
        public void Start()
        {
            if (!this._getNHCThread.IsAlive)
            {
                this._getNHCThread = new Thread(new ThreadStart(this.RunGetNHSThread));
                this._getNHCThread.Name = "NHCGetterThread";
                this._getNHCThread.IsBackground = true;
                this._getNHCThread.Start();
            }
        }

        public void Stop()
        {
            if (this._getNHCThread != null)
                this._getNHCThread.Interrupt();
            try
            {
                this._ftp.QuitImmediately();
            }
            catch (Exception)
            {
                return;
            }
        }

        #endregion

        #region Thread Method
        private void RunGetNHSThread()
        {
            // Sleep time will vary, initialize to _sleepTimeMillis
            int millis = _sleepMillis;

            // Poll for data every <_sleepMillis> 
            while (true)
            {
                try
                {
                    lock (_ftp)
                    {
                        #region Connect
                        _ftp.Timeout = 45000;
                        _ftp.RemoteHost = "ftp.nhc.noaa.gov";
                        _ftp.Connect();
                        _ftp.Login("anonymous", "me@home.com");
                        _ftp.ConnectMode = FTPConnectMode.PASV;
                        _ftp.TransferType = FTPTransferType.ASCII;
                        _ftp.ChDir("/pub/products/nhc/disc");
                        #endregion

                        #region Check Connection
                        if (!_ftp.IsConnected)
                        {
                            millis = 60 * 1000;
                            throw new Exception("FTP client not connected...retrying in 60 secs");
                        }
                        #endregion

                        #region Get most recent Storms and raise an event for those listening
                        FTPFile[] detls = _ftp.DirDetails(".");
                        ArrayList latest = new ArrayList();


                        // Check the last 10 for age
                        for (int i = 1; i < 11; i++)
                        {
                            // Construct partial filename strings based on Date
                            DateTime now = DateTime.UtcNow;
                            string year = now.Year.ToString();
                            string month = string.Format("{0:00}", now.Month);
                            string day = string.Format("{0:00}", now.Day);
                            string partDT = year + month + day;

                            now = now.AddDays(-1);
                            year = now.Year.ToString();
                            month = string.Format("{0:00}", now.Month);
                            day = string.Format("{0:00}", now.Day);
                            string partDT1 = year + month + day;

                            // Previous 2 days (today + yesterday)
                            if (((FTPFile)detls[detls.Length - i]).Name.Contains(partDT) ||
                                ((FTPFile)detls[detls.Length - i]).Name.Contains(partDT1))
                            {
                                latest.Insert(0, detls[detls.Length - i]);
                            }
                        }

                        // Get and parse ALL of the most recent NHC data
                        List<NHCDiscussion> tmpList = new List<NHCDiscussion>();
                        foreach (FTPFile ff in latest)
                        {
                            byte[] b = _ftp.Get(ff.Name);
                            foreach (NHCDiscussion s in NHCDiscussion.ParseNHC(b))
                            {
                                tmpList.Add(s);
                            }
                        }

                        // Now we have a list of recent storms, possibly duplicates that we should raise an event for
                        if (this.DiscussionRetrieved != null)
                            this.DiscussionRetrieved(tmpList);

                        #endregion
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(DateTime.Now.ToString() + " " + Thread.CurrentThread.Name + ":\n" + e.Message + "\n");
                }
                finally
                {
                    #region Close Connection
                    _ftp.Quit();
                    #endregion
                }
                try
                {
                    Thread.Sleep(millis);
                }
                catch (ThreadInterruptedException)
                {
                    return;
                }

                // Reset Sleep time to normal in case we slept short for an ftp connect problem
                millis = _sleepMillis;
            }
        }
        #endregion
    }
}